// kernel make menuconfig:
// General setup  --->
//         [ ] POSIX Message Queues  -> [*] POSIX Message Queues

#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <mqueue.h>
#include <pthread.h>

#include "./m_timespec.h"

#define MAX_SIZE 512
#define MSG_QUEUE_NAME "/test_msg_queue"

int mq_receive_timeout(mqd_t mq, char *buffer, int len, int msecs)
{
    int bytes;
    struct timespec timeout;

    if (msecs < 0)
    {
        bytes = mq_receive(mq, buffer, len, NULL);
    }
    else
    {
        timeout = ms2timespec(msecs);
        bytes = mq_timedreceive(mq, buffer, len, NULL, &timeout);
    }

    return bytes;
}

void *thr_fn(void *arg)
{
    mqd_t mq = *(mqd_t *)arg;
    char buffer[1024];
    while (1)
    {
        if (mq_receive_timeout(mq, buffer, sizeof(buffer), 1000) < 0)
        {
            printf("mq_receive error, %s\n", strerror(errno));
            continue;
        }
        printf("receive(%s)\n", buffer);
        if (buffer[0] == '9')
            break;
    }

    pthread_exit(NULL);
}

int main(int argc, char const *argv[])
{
    mqd_t mq;
    char message[64] = {0};

    if (0)
    {
        mq = mq_open(MSG_QUEUE_NAME, O_WRONLY);
        if ((mqd_t)-1 == mq)
        {
            printf("mq_open error, %s\n", strerror(errno));
            return 0;
        }
    }
    else
    {
        struct mq_attr attr;
        /* initialize the queue attributes */
        attr.mq_flags = 0;
        attr.mq_maxmsg = 10;
        attr.mq_msgsize = MAX_SIZE;
        attr.mq_curmsgs = 0;

        /* create the message queue */
        mq = mq_open(MSG_QUEUE_NAME, O_CREAT | O_RDWR, 0644, &attr);
        if ((mqd_t)-1 == mq)
        {
            printf("mq_open error, %s\n", strerror(errno));
            return 0;
        }
    }

    struct mq_attr mqAttr;
    if (mq_getattr(mq, &mqAttr) == 0)
    {
        printf("mq_flags:%ld\n", mqAttr.mq_flags);
        printf("mq_maxmsg:%ld\n", mqAttr.mq_maxmsg);
        printf("mq_msgsize:%ld\n", mqAttr.mq_msgsize);
        printf("mq_curmsgs:%ld\n", mqAttr.mq_curmsgs);
    }

    //创建线程去测试接收，或使用进程打开相同名称的消息队列
    pthread_t tid;
    int err = pthread_create(&tid, NULL, thr_fn, &mq);
    if (err != 0)
    {
        printf("can't create thread\n");
        return 0;
    }

    //发送消息
    sleep(4);
    for (int i = 0; i < 10; i++)
    {
        message[0] = '0' + i;
        if (mq_send(mq, message, strlen(message), 0) != 0)
        {
            printf("mq_send error,%s\n", strerror(errno));
            return 0;
        }
    }
    pthread_join(tid, NULL);

    //关闭一个进程中使用的消息队列描述符，消息队列本身依然存在，其中的消息也都会保存。
    if (mq_close(mq) != 0)
    {
        printf("mq_close error, %s\n", strerror(errno));
        return 0;
    }

    //用于删除消息队列的name，如果存在打开的描述符，那么该消息队列依然可用，直到所有打开的描述符都关闭后才会destory
    if (mq_unlink(MSG_QUEUE_NAME) != 0)
    {
        printf("mq_unlink error, %s\n", strerror(errno));
        return 0;
    }

    return 0;
}
